package com.jieyun.rbac.service.impl;

import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.jieyun.core.exception.ParamException;
import com.jieyun.core.utils.ServerResponse;
import com.jieyun.core.utils.SessionUtils;
import com.jieyun.rbac.constant.RBACConstant;
import com.jieyun.rbac.dto.DeptTreeDTO;
import com.jieyun.rbac.mapper.SysDeptMapper;
import com.jieyun.rbac.param.DeptParam;
import com.jieyun.rbac.po.SysDept;
import com.jieyun.rbac.service.SysDeptService;
import com.jieyun.rbac.utils.LevelUtils;

/**
 * 组织部门服务
 * @author trekxu
 *
 */
@Service
public class SysDeptServiceImpl implements SysDeptService {

	@Resource
	private SysDeptMapper sysDeptMapper;

	// 默认第一层的节点的父id都是为0的,这样方便以后查询等操作
	public static Integer DEFAULT_ROOT_PARENT_ID = 0;

	@Override
	public ServerResponse save(DeptParam dept) {

		if (dept == null) {
			throw new ParamException("没有传递部门参数!");
		}

		if (dept.getParentId() == null) {
			dept.setParentId(DEFAULT_ROOT_PARENT_ID);
		}

		// 进行校验,同一层级下面不能有相同名称的部门
		if (!checkDeptName(dept.getParentId(), dept.getName())) {
			return ServerResponse.fail("在同层级下不能存在相同名称的部门");
		}

		SysDept sysDept = new SysDept();
		BeanUtils.copyProperties(dept, sysDept);

		// 计算level
		SysDept parentDept = sysDeptMapper.selectById(sysDept.getParentId());
		if (parentDept != null) {
			sysDept.setLevel(LevelUtils.calLevel(parentDept.getLevel(), String.valueOf(parentDept.getId())));
		} else {
			sysDept.setLevel(LevelUtils.ROOT_LEVEL);
		}

		sysDept.setOperator(SessionUtils.getSysUser().getName());
		sysDept.setOperateTime(new Date());

		int count = this.sysDeptMapper.insert(sysDept);
		if (count == 0) {
			return ServerResponse.fail("新增部门错误!");
		}

		return ServerResponse.ok(null, "新增部门成功!");
	}

	/**
	 * 校验同一层级下是否存在相同名称的部门
	 * 
	 * @param parentId
	 * @param name
	 * @return
	 */
	private boolean checkDeptName(Integer parentId, String name) {
		return this.sysDeptMapper
				.selectCount(new EntityWrapper<SysDept>(SysDept.builder().parentId(parentId).name(name).status(RBACConstant.DeptStatus.ok).build()))
					== 0;
	}

	/**
	 * 将部门的信息转换为树形结构
	 * 
	 * @return
	 */
	public ServerResponse listTree() {

		// 获取所有的节点
		List<SysDept> deptList = sysDeptMapper.selectList(new EntityWrapper<SysDept>(SysDept.builder().status(RBACConstant.DeptStatus.ok).build()));
		// 获取适配对象
		List<DeptTreeDTO> dtoList = Lists.newArrayList();
		deptList.forEach((e) -> {
			dtoList.add(DeptTreeDTO.adapt(e));
		});

		// 转换为multiMap结构,其中键就是父id,后面就靠这个父id进行递归处理
		ListMultimap<Integer, DeptTreeDTO> multimap = ArrayListMultimap.create();
		dtoList.forEach((e) -> {
			multimap.put(e.getParentId(), e);
		});

		// 将相同父id的list进行排序操作
		multimap.keySet().forEach(e -> {
			Collections.sort(multimap.get(e), (a, b) -> {
				return a.getSeq() - b.getSeq();
			});
		});

		// 选出根节点
		List<DeptTreeDTO> rootDto = multimap.get(DEFAULT_ROOT_PARENT_ID);

		return ServerResponse.ok(doTree(multimap, rootDto));
	}

	/***
	 * 递归生成树形结构
	 * 
	 * @param id
	 * @param multimap
	 * @param rootDto
	 * @return
	 */
	private List<DeptTreeDTO> doTree(ListMultimap<Integer, DeptTreeDTO> sourceMapList, List<DeptTreeDTO> treeList) {

		treeList.forEach(e -> {
			e.setChildren(sourceMapList.get(e.getId()));
			doTree(sourceMapList, e.getChildren());
		});

		return treeList;
	}
	
	/**
	 * 删除组织部门信息
	 */
	@Override
	public ServerResponse deleteDept(Integer id) {
		if(id == null) {
			return ServerResponse.fail("删除的部门id不能为空");
		}
		
		// 先判断是否存在下级的部门
		if(checkExistsSubDept(id)) {
			return ServerResponse.fail("删除的部门存在子部门");
		}
		
		// 此时可以正常的删除掉部门(状态值改成droped)
		SysDept dept = SysDept
							.builder()
							.id(id)
							.status(RBACConstant.DeptStatus.droped)
							.operateTime(new Date())
							.operator(SessionUtils.getSysUser().getName())
							.build();
		int count = this.sysDeptMapper.updateById(dept);
		if(count == 0) {
			return ServerResponse.fail("删除部门失败!");
		}
		return ServerResponse.ok("删除部门成功!");
	}

	/**
	 * 判断部门下是否存在子部门
	 * @param id
	 * @return
	 */
	private boolean checkExistsSubDept(Integer id) {
		// 看看父id相同的部门的数量是否为0
		return this.sysDeptMapper
					.selectCount(new EntityWrapper<SysDept>(SysDept.builder().parentId(id).status(RBACConstant.DeptStatus.ok).build())) != 0;
	}
	
	/**
	 * 更新部门信息
	 */
	@Override
	public ServerResponse updateDept(Integer id, String name, String remark, Integer seq) {
		if(id == null) {
			return ServerResponse.fail("更新的部门的id不能为空");
		}
		
		if(StringUtils.isBlank(name)) {
			return ServerResponse.fail("部门的名称不能为空");
		}
		
		SysDept dept = this.sysDeptMapper.selectById(id);
		
		if(StringUtils.equals(name, dept.getName())) {
			return ServerResponse.fail("修改前后的名称一致");
		}
		
		//判断是否在同一层级下有相同的部门
		if(!checkExistsSubDept(dept.getParentId())) {
			return ServerResponse.fail("在同一层级下存在相同的部门名称");
		}
		
		// 更新部门的信息
		dept = SysDept.builder()
							.id(id)
							.name(name)
							.remark(remark)
							.seq(seq)
							.operateTime(new Date())
							.operator(SessionUtils.getSysUser().getName())
							.build();
		
		int count =  this.sysDeptMapper.updateById(dept);
		if(count == 0) {
			return ServerResponse.fail("更新部门失败");
		}
		return ServerResponse.ok("更新部门成功");
	}

	@Override
	public ServerResponse deptList() {
		List<SysDept> deptList = sysDeptMapper.selectList(new EntityWrapper<SysDept>(SysDept.builder().status(RBACConstant.DeptStatus.ok).build()));
		return ServerResponse.ok(deptList);
	}
}
